package net.sk.china.city.talk.service.impl.system;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import net.sk.china.city.talk.constants.Constants;
import net.sk.china.city.talk.dao.system.SystemRoleDao;
import net.sk.china.city.talk.model.system.CityAdmin;
import net.sk.china.city.talk.model.system.CityMenu;
import net.sk.china.city.talk.model.system.CityRole;
import net.sk.china.city.talk.model.system.CityRoleMenu;
import net.sk.china.city.talk.request.system.SystemRoleRequest;
import net.sk.china.city.talk.request.system.SystemRoleSearchRequest;
import net.sk.china.city.talk.response.CategoryTreeResponse;
import net.sk.china.city.talk.response.menu.MenuCheckResponse;
import net.sk.china.city.talk.response.system.LoginSystemResponse;
import net.sk.china.city.talk.response.system.RoleInfoResponse;
import net.sk.china.city.talk.service.CategoryService;
import net.sk.china.city.talk.service.system.SystemMenuService;
import net.sk.china.city.talk.service.system.SystemRoleMenuService;
import net.sk.china.city.talk.service.system.SystemRoleService;
import net.sk.china.city.talk.utils.MenuCheckTreeUtil;
import net.sk.china.common.exception.TalkException;
import net.sk.china.common.request.PageParamRequest;
import net.sk.china.common.utils.TalkUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * SystemRoleServiceImpl 接口实现
 * +----------------------------------------------------------------------
 * // | Talk To [ 聊来改善地区金融服务环境，助力企业发展 ]
 * // +----------------------------------------------------------------------
 * // | Copyright (c) 2018-2024 聊来 All rights reserved.
 * // +----------------------------------------------------------------------
 * // | Licensed ( <a href="http://www.apache.org/licenses/LICENSE-2.0">apache</a> )
 * // +----------------------------------------------------------------------
 * // | @Author: 聊来 <18970881148@qq.com>
 * // +----------------------------------------------------------------------
 * // | DateTime: 2024/6/3 15:37
 * // +----------------------------------------------------------------------
 */

@Service
public class SystemRoleServiceImpl extends ServiceImpl<SystemRoleDao, CityRole> implements SystemRoleService {

    @Resource
    private SystemRoleDao dao;

    private final CategoryService categoryService;

    private final TransactionTemplate transactionTemplate;

    private final SystemRoleMenuService systemRoleMenuService;

    private final SystemMenuService systemMenuService;

    public SystemRoleServiceImpl(CategoryService categoryService, TransactionTemplate transactionTemplate, SystemRoleMenuService systemRoleMenuService, SystemMenuService systemMenuService) {
        this.categoryService = categoryService;
        this.transactionTemplate = transactionTemplate;
        this.systemRoleMenuService = systemRoleMenuService;
        this.systemMenuService = systemMenuService;
    }

    /**
     * 获取所有角色
     * @return {@code List<SystemRole>}
     */
    @Override
    public List<CityRole> getAllList() {
        LambdaQueryWrapper<CityRole> query = new LambdaQueryWrapper<>();
        query.eq(CityRole::getStatus, true);
        query.orderByAsc(CityRole::getId);
        return dao.selectList(query);
    }

    /**
     * 列表
     * @param request 请求参数
     * @param pageParamRequest 分页类参数
     * @return {@code List<SystemRole>}
     */
    @Override
    public List<CityRole> getList(SystemRoleSearchRequest request, PageParamRequest pageParamRequest) {
        PageHelper.startPage(pageParamRequest.getPage(), pageParamRequest.getLimit());
        LambdaQueryWrapper<CityRole> query = new LambdaQueryWrapper<>();
        query.select(CityRole::getId, CityRole::getRoleName, CityRole::getStatus,
                CityRole::getCreateTime, CityRole::getUpdateTime);
        if (ObjectUtil.isNotNull(request.getStatus())) {
            query.eq(CityRole::getStatus, request.getStatus());
        }
        if (ObjectUtil.isNotNull(request.getRoleName())) {
            query.like(CityRole::getRoleName, request.getRoleName());
        }
        query.orderByAsc(CityRole::getId);
        return dao.selectList(query);
    }

    /**
     * 根据id集合获取对应权限列表
     * @param ids id集合
     * @return {@code List<SystemRole>}
     */
    @Override
    public List<CityRole> getListInIds(List<Integer> ids) {  return dao.selectBatchIds(ids); }

    /**
     * 管理员菜单权限
     * @return {@code List<CategoryTreeResponse>}
     */
    @Override
    public List<CategoryTreeResponse> menu() {
        List<Integer> categoryIdList = getRoleListInRoleId();
        return categoryService.getListTree(Constants.CATEGORY_TYPE_MENU, 1, categoryIdList);
    }

    /**
     * 修改身份状态
     * @param id 数据ID
     * @param status 状态
     * @return {@code boolean}
     */
    @Override
    public boolean updateStatus(Integer id, Boolean status) {
        CityRole role = getById(id);
        if (ObjectUtil.isNull(role)) {
            throw new TalkException("身份不存在");
        }
        if (role.getStatus().equals(status)) {
            return true;
        }
        role.setStatus(status);
        return updateById(role);
    }

    /**
     * 添加身份
     * @param systemRoleRequest 身份参数
     * @return {@code Boolean}
     */
    @Override
    public Boolean add(SystemRoleRequest systemRoleRequest) {
        if (existName(systemRoleRequest.getRoleName(), 0)) {
            throw new TalkException("角色名称重复");
        }
        List<Integer> ruleList = Stream.of(systemRoleRequest.getRules().split(",")).map(Integer::valueOf).distinct().collect(Collectors.toList());
        CityRole cityRole = new CityRole();
        BeanUtils.copyProperties(systemRoleRequest, cityRole);
        cityRole.setId(null);
        cityRole.setRules("");

        return transactionTemplate.execute(e -> {
            boolean save = save(cityRole);
            if (!save) {
                return Boolean.FALSE;
            }
            List<CityRoleMenu> roleMenuList = ruleList.stream().map(rule -> {
                CityRoleMenu roleMenu = new CityRoleMenu();
                roleMenu.setRid(cityRole.getId());
                roleMenu.setMenuId(rule);
                return roleMenu;
            }).collect(Collectors.toList());
            systemRoleMenuService.saveBatch(roleMenuList, 100);
            return Boolean.TRUE;
        });
    }

    /**
     * 修改身份管理表
     * @param systemRoleRequest 修改参数
     * @return {@code Boolean}
     */
    @Override
    public Boolean edit(SystemRoleRequest systemRoleRequest) {
        CityRole role = getById(systemRoleRequest.getId());
        if (ObjectUtil.isNull(role)) {
            throw new TalkException("角色不存在");
        }
        if (!role.getRoleName().equals(systemRoleRequest.getRoleName())) {
            if (existName(systemRoleRequest.getRoleName(), systemRoleRequest.getId())) {
                throw new TalkException("角色名称重复");
            }
        }
        CityRole cityRole = new CityRole();
        BeanUtils.copyProperties(systemRoleRequest, cityRole);
        cityRole.setRules("");
        List<Integer> ruleList = Stream.of(systemRoleRequest.getRules().split(",")).map(Integer::valueOf).distinct().collect(Collectors.toList());
        List<CityRoleMenu> roleMenuList = ruleList.stream().map(rule -> {
            CityRoleMenu roleMenu = new CityRoleMenu();
            roleMenu.setRid(cityRole.getId());
            roleMenu.setMenuId(rule);
            return roleMenu;
        }).collect(Collectors.toList());
        return transactionTemplate.execute(e -> {
            updateById(cityRole);
            systemRoleMenuService.deleteByRid(cityRole.getId());
            systemRoleMenuService.saveBatch(roleMenuList, 100);
            return Boolean.TRUE;
        });
    }

    /**
     * 删除角色
     * @param id 角色id
     * @return {@code Boolean}
     */
    @Override
    public Boolean delete(Integer id) {
        CityRole cityRole = getById(id);
        if (ObjectUtil.isNull(cityRole)) {
            throw new TalkException("角色已删除");
        }
        return transactionTemplate.execute(e -> {
            dao.deleteById(id);
            systemRoleMenuService.deleteByRid(id);
            return Boolean.TRUE;
        });
    }

    /**
     * 获取角色详情
     * @param id 角色id
     * @return {@code RoleInfoResponse}
     */
    @Override
    public RoleInfoResponse getInfo(Integer id) {
        CityRole cityRole = getById(id);
        if (ObjectUtil.isNull(cityRole)) {
            throw new TalkException("角色不存在");
        }
        // 查询角色对应的菜单(权限)
        List<CityMenu> menuList = systemMenuService.getCacheList();
        List<Integer> menuIdList = systemRoleMenuService.getMenuListByRid(id);

        List<MenuCheckResponse> menuCheckVoList = menuList.stream().map(menu -> {
            MenuCheckResponse menuCheckVo = new MenuCheckResponse();
            BeanUtils.copyProperties(menu, menuCheckVo);
            if (menuIdList.contains(menu.getId())) {
                menuCheckVo.setChecked(true);
            } else {
                menuCheckVo.setChecked(false);
            }
            return menuCheckVo;
        }).collect(Collectors.toList());

        RoleInfoResponse response = new RoleInfoResponse();
        BeanUtils.copyProperties(cityRole, response);
        response.setMenuList(new MenuCheckTreeUtil(menuCheckVoList).buildTree());
        return response;
    }

    /**
     * 获取管理员信息（从security中）
     * @return {@code SystemAdmin}
     */
    @Override
    public CityAdmin getSystemAdminInfo() {
        LoginSystemResponse vo = getLoginSystemVo();
        List<String> roleList = Stream.of(vo.getUser().getRoles().split(",")).collect(Collectors.toList());

        CityAdmin cityAdmin = vo.getUser();
        cityAdmin.setRoles(roleList.contains("1") ? "1" : "0");

        return cityAdmin;
    }

    /**
     * 判断角色名称是否存在
     * @param roleName 角色名称
     * @param id 角色id
     * @return Boolean
     */
    private Boolean existName(String roleName, Integer id) {
        LambdaQueryWrapper<CityRole> query = Wrappers.lambdaQuery();
        query.eq(CityRole::getRoleName, roleName);
        if (ObjectUtil.isNotNull(id) || id != Constants.NUM_ZERO) { query.ne(CityRole::getId, id); }
        query.last(" limit 1");
        Long count = dao.selectCount(query);
        return count > 0;
    }

    /**
     * 获取当前用户的所有权限
     * @return List<Integer>
     */
    private List<Integer> getRoleListInRoleId(){
        LoginSystemResponse loginSystemVo = getLoginSystemVo();
        CityAdmin cityAdmin = loginSystemVo.getUser();
        if (null == cityAdmin || StringUtils.isBlank(cityAdmin.getRoles())){
            throw new TalkException("没有权限访问！");
        }

        //获取用户权限组
        List<CityRole> cityRoleList = getVoListInId(cityAdmin.getRoles());
        if (cityRoleList.size() < 1){
            throw new TalkException("没有权限访问！");
        }

        //获取用户权限规则
        List<Integer> categoryIdList = new ArrayList<>();
        for (CityRole cityRole : cityRoleList) {
            if (StringUtils.isBlank(cityRole.getRules())){
                continue;
            }

            categoryIdList.addAll(TalkUtil.stringToArray(cityRole.getRules()));
        }

        return categoryIdList;
    }

    private List<CityRole> getVoListInId(String roles) {
        LambdaQueryWrapper<CityRole> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(CityRole::getId, TalkUtil.stringToArray(roles));
        return dao.selectList(lambdaQueryWrapper);
    }

    /**
     * 获取管理员信息（从security中）
     */
    private LoginSystemResponse getLoginSystemVo() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginSystemResponse loginSystemVo = (LoginSystemResponse) authentication.getPrincipal();
        if (ObjectUtil.isNull(loginSystemVo)) {
            throw new TalkException("登录信息已过期，请重新登录");
        }
        return loginSystemVo;
    }
}
